<?php
/**
 *
 * @author ninetyseven.
 * @date 2023-03-27 22:53
 */

namespace App\Services;


use App\Enum\DriverEnum;
use App\Enum\DriverMileageEnum;
use App\Enum\OrderEnum;
use App\Enum\TravelEnum;
use App\Enum\VehicleExceptionEnum;
use App\Enum\VillagerEnum;
use App\Enum\WalletsEnum;
use App\Models\ContractorModel;
use App\Models\DriverCartModel;
use App\Models\DriverMileageModel;
use App\Models\DriverModel;
use App\Models\DriverRealModel;
use App\Models\OrderModel;
use App\Models\OrdersAppealModel;
use App\Models\VehicleExceptionModel;
use App\Models\VillagerUserModel;
use App\Models\WalletModel;
use Illuminate\Support\Facades\DB;
use Exception;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

class DriverService extends BaseService
{
    public const DRIVER_ORDER_REDIS_ID = 'driver:order:id:%s';

    /**
     * 司机信息注册
     * @throws Exception
     * @author ninetyseven.
     * @date 2023-03-28 0:17
     */
    public static function registerDriverInfo($post)
    {
        return DriverModel::create([
            'phone' => $post['phone'],
            'password' => md5Password($post['password']),
        ]);
    }

    /**
     * 生成预警订单
     * @param int $orderId
     * @return bool
     * @throws Exception
     */
    public function addWaringOrder(int $orderId = 0): bool
    {
        $orderInfo = OrderModel::query()->where('id', $orderId)->first();
        if (!$orderInfo) {
            throw new  Exception('订单不存在');
        }

        if ($orderInfo['status'] != OrderEnum::STATUS_DRIVING) {
            throw new  Exception('订单不在行驶中');
        }

        $orderInfo->is_warning = OrderEnum::ORDER_WARNING_YES;
        if (!$orderInfo->save()) {
            throw new  Exception('更新订单失败');
        }

        return true;
    }

    /**
     * 修改密码
     * @param $post
     * @return bool
     * @throws Exception
     * @author ninetyseven.
     * @date 2023-03-28 21:52
     */
    public static function modifyPassword($post): bool
    {
        $info = DriverModel::query()->where('phone', $post['phone'])->first();
        if (!$info) {
            throw new Exception('账号不存在');
        }

        $info->password = md5Password($post['password']);
        if (!$info->save()) {
            throw new Exception('修改密码失败');
        }
        return true;
    }


    /**
     * 获取司机信息.
     * @param int $userId
     * @return array
     * @throws Exception
     */
    public function getDriverInfo(int $userId = 0): array
    {
        if (empty($userId)) {
            $userId = \request()->userId;
        }
        $info = DriverModel::where('id', $userId)->first();
        if (!$info) {
            throw new Exception('司机信息不存在');
        }

        if ($info->status == VillagerEnum::ACCOUNT_STATUS_CANCELLATION) {
            throw new Exception('司机账号已注销');
        }

        if (in_array($info->status, [1, 3])) {
            $info->status = 1;
        } else {
            $info->status = 2;
        }


        if (!empty($info->user_id)) {
            $info = VillagerUserModel::query()->where('id', $info->user_id)->first();
        }
        $info['enterprise_id'] = 0;             // 司机APP 专用 字段20231024 by LC
        $info['go_on_work_time'] = 0;           // 司机APP 专用 字段20231024 by LC
        $info['go_off_work_time'] = 0;// 司机APP 专用 字段20231024 by LC
        $cart = DriverCartModel::query()->select()->where('driver_id', $info->id)->first();
        if (!$cart) {
            $info['cart_info'] = [];
        } else {
            $info['cart_info'] = $cart->toArray();
            $info['car_plate_number'] = $info['cart_info']['cart_number'];
        }
        return $info->toArray();
    }

    /**
     * 异常上报
     * @throws Exception
     * @author ninetyseven.
     * @date 2023-04-02 15:58
     */
    public function addAbnormal(array $params = []): bool
    {
        if (empty($params['reason'])) {
            throw new Exception('故障原因不能为空');
        }

        if (count($params['images']) > VehicleExceptionEnum::IMAGE_COUNT) {
            throw new Exception('图片上传张数超过限制');
        }

        $userId = \request()->userId;
        $platformId = self::getPlatformId();
        if ($platformId == TravelEnum::PLATFORM_DRIVER) {
            $info = DriverModel::query()->where('id', $userId)->select('car_plate_number')->first();
        } else {
            $info = VillagerUserModel::query()->where('id', $userId)->select()->first();
        }

        if (!$info) {
            throw new Exception('用户信息不存在');
        }

        $addData = [
            'license_plate' => isset($info['car_plate_number']) ? $info['car_plate_number'] : '',
            'user_id' => $userId,
            // 1-司机 2-用户
            'user_type' => $platformId == TravelEnum::PLATFORM_DRIVER ? 1 : 2,
            'reason' => $params['reason'],
            'image' => $images = is_array($params['images']) ? implode(',', $params['images']) : '',
        ];

        $res = VehicleExceptionModel::query()->create($addData);
        if (!$res) {
            throw new Exception('异常上报失败');
        }

        return true;
    }

    /**
     * 司机实名信息.
     * @return array
     * @throws Exception
     * @author ninetyseven.
     * @date 2023-04-02 20:36
     */
    public function getAuthInfo(): array
    {
        $userId = \request()->userId;

        $driverInfo = DriverRealModel::query()->where('driver_id', $userId)->select()->first();
        if (!$driverInfo) {
            throw new Exception('司机尚未实名');
        }
        return $driverInfo->toArray();
    }

    /**
     * 获取车辆信息.
     * @return array
     * @throws Exception
     * @author ninetyseven.
     * @date 2023-04-02 20:36
     */
    public function getCartInfo(): array
    {
        $userId = \request()->userId;
        return DriverCartModel::query()->where('driver_id', $userId)->select()->first()->toArray();
    }

    /**
     * 停止接单(修改司机状态)
     * @throws Exception
     * @author ninetyseven.
     * @date 2023-04-02 22:36
     */
    public function modifyDriverStopOrder(): bool
    {
        $userId = \request()->userId;
        $driver = DriverModel::query()->find($userId);
        if (!$driver) {
            throw new Exception('司机信息不存在');
        }

        $driver->status = DriverEnum::DRIVER_STATUS_OFF;
        if (!$driver->save()) {
            throw new Exception('司机状态更新失败');
        }
        return true;
    }

    /**
     * 完成订单后修改距离
     * modifyOrderDistance
     * @param array $params
     * @return true
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     * @author ninetyseven.
     * @date 2023/5/8
     */
    public function modifyOrderDistance(array $params = []): bool
    {
        //接收传入的距离
        $km = $params['km'] ?? '';
        if (empty($km)) {
            throw new Exception('距离不能为空');
        }

        //订单核销成功后，修改订单里程
        $redis = app("redis.connection");
        $key = sprintf(self::DRIVER_ORDER_REDIS_ID, request()->userId);
        if (!$redis->exists($key)) {
            throw new Exception('订单不存在');
        }

        $orderId = $redis->get($key);
        $orderInfo = OrderModel::query()->where('id', $orderId)->first();

        if (!$orderInfo) {
            throw new Exception('订单不存在');
        }

        $orderInfo->distance = $km;
        if (!$orderInfo->save()) {
            throw new Exception('订单里程修改失败');
        }

        return true;
    }

    /**
     * 开始接单(修改司机状态)
     * modifyDriverStartOrder
     * @return bool
     * @throws Exception
     * @author ninetyseven.
     * @date 2023/4/30
     */
    public function modifyDriverStartOrder(): bool
    {
        $userId = \request()->userId;
        $driver = DriverModel::query()->find($userId);
        if (!$driver) {
            throw new Exception('司机信息不存在');
        }

        $driver->status = DriverEnum::DRIVER_STATUS_OK;
        if (!$driver->save()) {
            throw new Exception('司机状态更新失败');
        }
        return true;
    }

    /**
     * 订单申诉上报
     * createOrderAppeal
     * @param array $params
     * @return true
     * @throws Exception
     * @author ninetyseven.
     * @date 2023/4/30
     */
    public function createOrderAppeal(array $params = []): bool
    {
        if (empty($params['reason'])) {
            throw new Exception('故障原因不能为空');
        }

        if (empty($params['order_id'])) {
            throw new Exception('订单id不能为空');
        }

        if (count($params['images']) > VehicleExceptionEnum::IMAGE_COUNT) {
            throw new Exception('图片上传张数超过限制');
        }

        $userId = \request()->userId;
        $info = DriverModel::query()->where('id', $userId)->select()->first();
        if (!$info) {
            throw new Exception('司机信息不存在');
        }

        $addData = [
            'order_id' => $params['order_id'],
            'user_id' => $userId,
            'abnormal_images' => is_array($params['images']) ? implode(',', $params['images']) : '',
            'abnormal_reasons' => $params['reason'],
            'status' => 1,
        ];

        $res = OrdersAppealModel::query()->create($addData);
        if (!$res) {
            throw new Exception('订单申诉失败');
        }

        return true;
    }

    /**
     * 抢单
     * @param array $params
     * @return bool
     * @throws Exception
     * @author ninetyseven.
     * @date 2023-04-05 11:46
     */
    public function orbOrderInfo(array $params = []): bool
    {
        throw new Exception("此方法已经废除@2023-12-26");
        $userId = request()->userId;
        $driver = DriverModel::query()->find($userId);
        if (!$driver) {
            throw new Exception('司机信息不存在');
        }

        if ($driver->status != DriverEnum::DRIVER_STATUS_OK) {
            throw new Exception('司机不在线或出行中');
        }

        // 查看缓存中是否记录
        $redis = app("redis.connection");
        $rodKey = sprintf(OrderService::REDIS_DRIVER_ROD_ORDER_KEY, $params['order_id']);
        if ($redis->exists($rodKey)) {
            throw new Exception('该订单已被抢单了');
        }

        //订单信息
        $orderInfo = OrderService::getOrderInfo($params['order_id'], true, OrderEnum::ORDER_TYPE_SERVICE, self::getPlatformId());
        if (empty($orderInfo)) {
            throw new Exception('订单错误');
        }
        //判断是否是服务订单
        if ($orderInfo['order_type'] != OrderEnum::ORDER_TYPE_SERVICE) {
            throw new Exception('该订单不是服务订单');
        }
        if ($orderInfo['status'] != OrderEnum::STATUS_PENDING_ORDER) {
            throw new Exception('该订单不能被抢单哦');
        }

        $driverData = CommonService::seizeOrders($orderInfo);
        if (!empty($driverData)) {
            $driverData = array_column($driverData, 'id');
            if (!in_array($driver->id, $driverData)) {
                throw new Exception('你暂时不能抢单');
            }

            //抢单
            $redis->set($rodKey, $userId);
            //更改订单状态
            $upOrder = [
                'driver_id' => $userId,
                'status' => OrderEnum::STATUS_PENDING_TRAVEL,
            ];
            $res = OrderService::updateOrderStatus($upOrder, $params['order_id']);
            if ($res === false) {
                DB::rollBack();
                return false;
            }

            // 更改司机状态
            $driver->status = DriverEnum::DRIVER_STATUS_DRIVING;
            if (!$driver->save()) {
                throw new Exception('司机状态更新失败');
            }

            DB::commit();
            return true;
        }

        return false;
    }


    /**
     * 获取承包信息
     * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model|object|null
     * @throws Exception
     * @author ninetyseven.
     * @date 2023-04-05 16:29
     */
    public function getEnterpriseInfo()
    {
        $userId = \request()->userId;
        $driver = DriverModel::query()->find($userId);
        if (!$driver) {
            throw new Exception('司机信息不存在');
        }
        if (empty($driver->enterprise_id)) {
            throw new Exception('司机未有承包信息');
        }

        return ContractorModel::query()->where('id', $driver->enterprise_id)->first();
    }

    /**
     * 保存里程
     * @param array $params
     * @return array
     * @throws Exception
     * @author ninetyseven.
     * @date 2023-04-05 17:18
     */
    public function mileageAdd(array $params = []): array
    {
        $toDayDate = date('Y-m-d', time());
        $userId = request()->userId;

        $saveData = [
            'driver_id' => $userId,
            'sign_date' => $toDayDate,
        ];

        if ($params['type'] == DriverMileageEnum::START_MILEAGE) {
            $saveData['start_mileage'] = $params['mileage'];
            $saveData['start_images'] = is_array($params['mileage_image']) ? implode(',', $params['mileage_image']) : '';
        } elseif ($params['type'] == DriverMileageEnum::END_MILEAGE) {
            $saveData['end_mileage'] = $params['mileage'];
            $saveData['end_images'] = is_array($params['mileage_image']) ? implode(',', $params['mileage_image']) : '';
        }

        $driverMileage = DriverMileageModel::query()->updateOrCreate([
            'driver_id' => $userId,
            'sign_date' => $toDayDate
        ], $saveData);

        if (!$driverMileage) {
            throw new Exception('保存里程失败');
        }

        return [
            'total_distance' => !empty($driverMileage['end_mileage']) ? bcsub($driverMileage['end_mileage'], $driverMileage['start_mileage']) : 0,
        ];
    }

    /**
     * 里程详情
     * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model|object|null
     * @throws Exception
     * @author ninetyseven.
     * @date 2023-04-05 18:05
     */
    public function mileageInfo()
    {
        $toDayDate = date('Y-m-d', time());
        $userId = request()->userId;

        $info = DriverMileageModel::query()->where('driver_id', $userId)->where('sign_date', $toDayDate)->first();
        if (!$info) {
            throw new Exception('信息不存在');
        }

        $info['total'] = !empty($info['end_mileage']) ? bcsub($info['end_mileage'], $info['start_mileage']) : 0;
        return $info;
    }

    /**
     * 历史里程
     * @return \Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection
     * @author ninetyseven.
     * @date 2023-04-05 18:10
     */
    public function getMileageHistoryList()
    {
        $userId = request()->userId;

        $data = DriverMileageModel::query()->where('driver_id', $userId)->get();
        if (!empty($data)) {
            foreach ($data as &$item) {
                $item['total'] = !empty($item['end_mileage']) ? bcsub($item['end_mileage'], $item['start_mileage']) : 0;
            }
            unset($item);
        }

        return $data;
    }
    public function OrdActivityOrder($orderId):bool
    {
        $orderInfo = OrderModel::query()->find($orderId);
        if (empty($orderInfo)) {
            throw new Exception('核销时，订单状不存在。');
        }
        if ($orderInfo['status'] !== OrderEnum::STATUS_DRIVING) {
            throw new Exception('订单状态没更新，不能被核销');
        }
        $orderTime = timeDiff(time(), $orderInfo['start_time'])['min'];
        $res = OrderModel::query()->where('id', $orderId)->update([
            'status' => OrderEnum::STATUS_SUCCESS,
            'end_time' => time(),
            'order_time' => max($orderTime, 0),
        ]);
        if (!$res) {
            throw new Exception('订单修改失败');
        }
        return true;

    }

    /**
     * 活动订单核销
     * @param array $orderList
     * @return bool
     * @throws Exception
     */
    public function writeActivityOffOrder(array $orderList = []): bool
    {
        if (empty($orderList)) {
            throw new Exception('订单不存在');
        }

        $orderList = array_column($orderList, null, 'user_id');
        $orderInfo = reset($orderList);
        if ($orderInfo['status'] !== OrderEnum::STATUS_DRIVING) {
            throw new Exception('订单状态没更新，不能被核销');
        }

        //查询用户钱包
        $userIds = array_column($orderList, 'user_id');
        $userWallet = WalletModel::query()->whereIn('user_id', $userIds)->where('user_type', WalletsEnum::WALLET_USER_VILLAGER)->get()->toArray();

        $userWallet = array_column($userWallet, null, 'user_id');

        foreach ($orderList as $userId => $order) {
            $orderTime = timeDiff($order['end_time'], $order['start_time'])['min'];

            $res = OrderModel::query()->where('id', $order['id'])->update([
                'status' => OrderEnum::STATUS_SUCCESS,
                'end_time' => time(),
                'order_time' => max($orderTime, 0),
            ]);
            if (!$res) {
                throw new Exception('订单修改失败');
            }

            if ($order['payment_method'] == OrderEnum::ORDER_PAY_DIGITAL) {
                if (isset($userWallet[$userId])) {
                    //数字人民币
                    if ($userWallet[$userId]['digital_balance'] - $order['amount'] < 0) {
                        throw new Exception('余额不足');
                    }
                    $upData['digital_balance'] = $userWallet[$userId]['digital_balance'] - abs($order['amount']);

                    $res = WalletModel::query()->where('user_id', $order['user_id'])->where('user_type', WalletsEnum::WALLET_USER_VILLAGER)->update($upData);
                    if (!$res) {
                        throw new Exception('钱包修改失败');
                    }

                    $res = CommonService::recordAmountLog([
                        'order_no' => $order['order_no'],
                        'user_id' => $order['user_id'],
                        'driver_id' => !empty($order['driver_id']) ? $order['driver_id'] : 0,
                        'user_type' => WalletsEnum::WALLET_USER_VILLAGER,
                        'amount' => $order['amount'],
                        'amount_type'=>OrderEnum::ORDER_PAY_DIGITAL,
                        'change_type' => WalletsEnum::WALLET_LOG_TYPE_IN,
                        'comment' => '活动订单出行消费',
                        'start_address' => $order['start_address'],
                        'end_address' => $order['end_address'],
                        'end_time' => !empty($order['end_time']) ? $order['end_time'] : 0,
                        'start_time' => $order['start_time'],
                    ]);
                    if (!$res) {
                        throw new Exception('记录钱包日志失败');
                    }
                }
            }
        }

        //查询用户钱包
        $driverWhere = [
            'user_id' => $orderInfo['driver_id'],
            'user_type' => WalletsEnum::WALLET_USER_DRIVER
        ];

        $driverWallet = WalletModel::query()->where($driverWhere)->first();
        if (!$driverWallet) {
            throw new Exception('司机钱包不存在');
        }

        $driverWallet = $driverWallet->toArray();
        //司机收入
        $upData = [];
        if ($orderInfo['payment_method'] == OrderEnum::ORDER_PAY_DIGITAL) {
            $sumAmount = array_sum(array_column($orderList, 'amount'));
            //数字人民币
            $upData['digital_balance'] = $driverWallet['digital_balance'] + abs($sumAmount);
        }
        // 修改司机订单金额
        (new CommonService())->changeInAmount($upData, $driverWhere);

        foreach ($orderList as $order) {
            $res = CommonService::recordAmountLog([
                'order_no' => $order['order_no'],
                'user_id' => $order['driver_id'],
                'driver_id' => !empty($order['driver_id']) ? $order['driver_id'] : 0,
                'user_type' => WalletsEnum::WALLET_USER_DRIVER,
                'amount' => $order['amount'],
                'amount_type'=>OrderEnum::ORDER_PAY_DIGITAL,
                'change_type' => WalletsEnum::WALLET_LOG_TYPE_IN,
                'comment' => '司机订单收入',
                'start_address' => $order['start_address'],
                'end_address' => $order['end_address'],
                'end_time' => !empty($order['end_time']) ? $order['end_time'] : time(),
                'start_time' => $order['start_time'],
            ]);

            if (!$res) {
                throw new Exception('记录钱包日志失败');
            }
        }

        //更改司机接单状态
        $driver = DriverModel::query()->where('id', $orderInfo['driver_id'])->first();
        if (!$driver) {
            throw new Exception('司机不存在');
        }

        $driver->status = DriverEnum::DRIVER_STATUS_OK;
        if (!$driver->save()) {
            throw new Exception('司机状态更新失败');
        }

        DB::commit();
        return true;
    }

    /**
     * 更新司机接客状态
     * @param array $params
     * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model|object
     * @throws Exception
     */
    public function updateOrderDriverTime(array $params = [])
    {
        $userId = $params['user_id'] ?? '';
        $orderNo = $params['order_no'] ?? '';
        $driverId = $params['driver_id'] ?? '';
        $field = $params['field'] ?? '';
        if (empty($userId)) {
            throw new Exception('用户id为空');
        }
        if (empty($orderNo)) {
            throw new Exception('订单为空');
        }
        if( empty($field) ){
            throw new Exception('时间字段为空');
        }

        $where = [
            'order_no'=> $orderNo,
            'driver_id' => $driverId,
            'user_id' => $userId,
        ];
        //查询订单
        $order = OrderModel::query()->where($where)->first();
        if (!$order) {
            throw new Exception('订单不存在');
        }
        $old_status = $order->status;

        if($order->driver_id != $driverId){
            throw new Exception('订单不属于该司机');
        }
        // 更新 司机接客时间与状态
        if ( $field == 'driver_start_time'){
            if ($order->status !== OrderEnum::STATUS_PENDING_TRAVEL) {
                throw new Exception('订单状态不是待出行，操作失败。');
            }
            $order->driver_start_time = date("Y-m-d H:i:s");
            $order->status = OrderEnum::STATUS_PICKUP_START;
        }
        // 更新 司机到达接客点的时间与状态
        if ( $field == 'driver_arrived_time'){
            if ($order->status !== OrderEnum::STATUS_PICKUP_START) {
                throw new Exception('订单状态不是接客状态，操作失败。'.$order->status);
            }
            $order->driver_arrived_time = date("Y-m-d H:i:s");
            $order->status = OrderEnum::STATUS_PICKUP_ARRIVED;
        }
        if (!$order->save()) {
            throw new Exception('订单修改失败');
        }
        $order->old_status = $old_status;
        // 清除缓存keys
        try {
            (new RedisKeysService())->deleteDriverOrderListKey($driverId);
        } catch (NotFoundExceptionInterface|ContainerExceptionInterface $e) {
            throw new Exception('清除缓存keys失败');
        }
        return $order;
    }

    /**
     * 订单核销
     * @param array $params
     * @return bool
     * @throws Exception
     * @author ninetyseven.
     * @date 2023-04-05 20:02
     */
    public function writeOffOrder(array $params = []): bool
    {
        throw new Exception('Driver Service 方法 writeOffOrder 已经作废。');
    }
}
